package com.netty.otherhandler;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;

/**
 * @author renyitong
 * @version 1.0.0
 * @createTime 2023年08月10日
 * @Description
 */
public class LongIdleNettyServer {

    public static void main(String[] args) throws InterruptedException {
        // 这里我们使用NioEventLoopGroup实现类即可，创建BossGroup和WorkerGroup
        // 当然还有EpollEventLoopGroup，但是仅支持Linux，这是Netty基于Linux底层Epoll单独编写的一套本地实现，没有使用NIO那套
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        // 创建服务端启动引导类
        ServerBootstrap bootstrap = new ServerBootstrap();
        // 链式编写，很棒
        bootstrap
                .group(bossGroup, workerGroup)   // 指定事件循环组
                .channel(NioServerSocketChannel.class)  // 指定为NIO的ServerSocketChannel
                .childHandler(new ChannelInitializer<SocketChannel>() { // 注意，这里的SocketChannel不是我们NIO里面的，是Netty的
                    @Override
                    protected void initChannel(SocketChannel channel) throws Exception {
                        //获取流水线，当我们需要处理客户端的数据时，实际上是像流水线一样在处理，这个流水线上可以有很多Handler
                        channel.pipeline()
                                .addLast(new StringDecoder())
                                // todo IdleStateHandler能够侦测连接空闲状态
                                // 第一个参数表示连接多少秒没有读操作时触发事件，第二个是写操作，第三个是读写操作都算，0表示禁用第三个
                                .addLast(new IdleStateHandler(10,10,0))
                                .addLast(new ChannelInboundHandlerAdapter() {
                                    @Override
                                    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                        System.out.println("收到客户端发送的消息: " + msg);
                                        ctx.channel().writeAndFlush("已收到!");
                                    }

                                    /**
                                     * todo 事件需要在ChannelInboundHandlerAdapter中进行监听处理
                                     * @param ctx
                                     * @param evt
                                     * @throws Exception
                                     */
                                    @Override
                                    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
                                        // 没想到吧，在这里时候进行调用的
                                        if (evt instanceof IdleStateEvent){
                                            IdleStateEvent event = (IdleStateEvent)evt;
                                            if (event.state() == IdleState.WRITER_IDLE){
                                                System.out.println("我好久没写了，我是不是谢尔比啊...");
                                                ctx.channel().close();
                                            }else if (event.state() == IdleState.READER_IDLE){
                                                System.out.println("好久没有读取到数据了,你是尊嘟假嘟啊...");
                                                ctx.channel().close();
                                            }
                                        }
                                    }
                                })
                                .addLast(new StringEncoder());
                    }
                });

        // 最后绑定端口，启动
        bootstrap.bind(8080);

    }


}
